home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
AMICUS
/
AMICUS26.ADF
/
SoundScape
/
LatticeExamples
/
crossfade.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-01-26
|
11KB
|
526 lines
/* CROSSFADE.C Cross fade loop generator for the
SoundScape sampler.
(c) 1987 Todor Fay
*/
#include "exec/exec.h"
#include "exec/types.h"
#include "intuition/intuition.h"
#include "soundscape.h"
#include "sampler.h"
/* Cross Fade Icon for Patch Panel: */
UWORD crossfadedata[] = { /* 36 x 11 */
0, 0, 0,
16383, 65535, 49152,
511, 65528, 0,
15887, 65287, 49152,
16368, 24831, 49152,
16383, 40959, 49152,
16368, 24831, 49152,
15887, 65287, 49152,
511, 65528, 0,
16383, 65535, 49152,
0, 0, 0,
65535, 65535, 61440,
49152, 4, 12288,
49152, 57544, 12288,
49153, 61700, 28672,
55792, 24812, 61440,
65535, 40959, 61440,
55792, 24812, 61440,
49153, 61444, 28672,
49152, 57544, 12288,
49152, 4, 12288,
65535, 65535, 61440,
};
struct Image crossfadeimage =
{ 0,0,36,11,2,crossfadedata,3,0,0 };
/* Edit window. This has the gadgets for selecting
sampler channel and octave, and Doing and Undoing
the cross fade. These intuition data structures
were generated with Power Windows.
*/
USHORT BorderVectors1[] = {0,0,107,0,107,10,0,10,0,0};
struct Border Border1 = {
-2,-1,
3,0,JAM1,
5,
BorderVectors1,
NULL
};
struct IntuiText IText1 = {
1,0,JAM2,
33,1,
NULL,
"Undo",
NULL
};
struct Gadget UndoGadget = {
NULL,
23,55,
104,9,
GADGHCOMP,
RELVERIFY,
BOOLGADGET,
(APTR)&Border1,
NULL,
&IText1,
0,
NULL,
8,
NULL
};
UBYTE SIBuffer7[4] =
"5";
struct StringInfo GadgetSI7 = {
SIBuffer7,
NULL,
0,
4,
0,
0,0,0,0,0,
0,
5,
NULL
};
USHORT BorderVectors2[] = {0,0,35,0,35,9,0,9,0,0};
struct Border Border2 = {
-2,-1,
1,0,JAM1,
5,
BorderVectors2,
NULL
};
struct IntuiText IText2 = {
2,0,JAM2,
-60,0,
NULL,
"Octave",
NULL
};
struct Gadget OctaveGadget = {
&UndoGadget,
95,28,
32,8,
GADGHCOMP,
LONGINT+RELVERIFY+STRINGCENTER,
STRGADGET,
(APTR)&Border2,
NULL,
&IText2,
0,
(APTR)&GadgetSI7,
7,
NULL
};
UBYTE SIBuffer6[4] =
"1";
struct StringInfo GadgetSI6 = {
SIBuffer6,
NULL,
0,
4,
0,
0,0,0,0,0,
0,
1,
NULL
};
USHORT BorderVectors3[] = {0,0,35,0,35,9,0,9,0,0};
struct Border Border3 = {
-2,-1,
1,0,JAM1,
5,
BorderVectors3,
NULL
};
struct IntuiText IText3 = {
2,0,JAM2,
-67,0,
NULL,
"Channel",
NULL
};
struct Gadget ChannelGadget = {
&OctaveGadget,
95,15,
32,8,
GADGHCOMP,
LONGINT+RELVERIFY+STRINGCENTER,
STRGADGET,
(APTR)&Border3,
NULL,
&IText3,
0,
(APTR)&GadgetSI6,
6,
NULL
};
USHORT BorderVectors4[] = {0,0,107,0,107,10,0,10,0,0};
struct Border Border4 = {
-2,-1,
3,0,JAM1,
5,
BorderVectors4,
NULL
};
struct IntuiText IText4 = {
1,0,JAM2,
12,1,
NULL,
"Cross Fade",
NULL
};
struct Gadget CrossFadeGadget = {
&ChannelGadget,
23,41,
104,9,
GADGHCOMP,
RELVERIFY,
BOOLGADGET,
(APTR)&Border4,
NULL,
&IText4,
0,
NULL,
5,
NULL
};
/* Gadget list */
struct NewWindow NewWindowStructure = {
0,0,
152,72,
0,1,
GADGETUP+CLOSEWINDOW+RAWKEY,
WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE
+ACTIVATE,
&CrossFadeGadget,
NULL,
" X Fade ",
NULL,
NULL,
30,20,
152,72,
WBENCHSCREEN
};
unsigned short thisport;
opencode(direction)
/* There is nothing to be initialised. However,
it would be nice to connect the console
keyboard to the sampler so the user can test
the cross fade loops, so make an OpenLink call.
FindMidiPort returns the port id, given the
name of the port. Actually, these two ports
have ids that are hard coded into SoundScape.
This is an example what you should do with
modules that are independantly loaded into
the system.
*/
unsigned char direction;
{
OpenLink(FindMidiPort("console keyboard"),
FindMidiPort("sampler"));
return(1);
}
closecode(direction)
unsigned char direction;
{
return(1);
}
clearsounddata(sounddata)
/* This routine frees up the sample buffer belonging
to the SoundData structure 'sounddata'.
*/
struct SoundData *sounddata;
{
if (sounddata->data)
FreeMem(sounddata->data,sounddata->length);
sounddata->data = 0;
sounddata->length = 0;
sounddata->loopstart = 0;
sounddata->loopend = 0;
sounddata->start = 0;
}
crossfade(sounddata)
/* This, the cross fade routine, operates on a
SoundData structure.
The cross fade is done on the region of the
sample between the two loop points. The
sample prior to the loop start is gradually
mixed in until it is in full force by the
end of the loop.
This is very straight forward, the only problem
encountered is a sample with a loop that
is longer than the part leading into the
loop. This is solved by having the cross fade
section be shorter - the length of the lead
in section.
*/
struct SoundData *sounddata;
{
char *sample; /* Points to sample */
unsigned short loop; /* Length of loop. */
unsigned short crosslength; /* Length of cross fade. */
unsigned short start; /* Start point. */
long result; /* Intermediate result. */
unsigned short a,b; /* Indexes into sample. */
unsigned short j; /* Loop index. */
loop = sounddata->loopend - sounddata->loopstart;
sample = &sounddata->data[sounddata->start];
start = sounddata->loopstart - sounddata->start;
/* If the loop is greater than the start segment, set
the crossfade to cover the last part of the loop,
equal to the starting segment.
*/
if (loop > start) {
crosslength = start;
a = 0;
b = loop;
}
/* Otherwise, set the crossfade to cover the entire
loop.
*/
else {
crosslength = loop;
a = start - loop;
b = start;
}
for (j = 0; j < crosslength; j++ ) {
result = (j * sample[a]);
result += (crosslength - j) * sample[b];
result = result / crosslength;
sample[b] = result;
a++;
b++;
}
}
void useredit()
/* This routine is called whenever the user clicks
twice on the cross fade icon. A window is opened
and four gadgets are presented. Two string
gadgets allow the user to select the octave and
channel of the sample they'd like to work on.
Two boolean gadgets are used to command the
cross fade and undo operations.
There are two SoundData structures. OldSound
is used to keep an old copy of the sample
around for undoing. CFSound is used to hold
the sample that gets cross faded.
RAWKEY events are passed on to the console
keyboard with the OutConsole command.
This is so the user can test the changed sound
without having to click on another window to
enable the Console Keyboard.
*/
{
struct IntuiMessage *message;
struct SoundData *oldsound, *cfsound;
short code, class;
struct Gadget *gadget;
struct Window *window;
short octave = 5;
short channel = 0;
oldsound = (struct SoundData *)
AllocMem(sizeof(*oldsound),MEMF_CLEAR);
if (!oldsound) return;
cfsound = (struct SoundData *)
AllocMem(sizeof(*cfsound),MEMF_CLEAR);
if (!cfsound) {
FreeMem(oldsound,sizeof(*oldsound));
return;
}
window = (struct Window *)
OpenWindow(&NewWindowStructure);
while (window) {
while (!(message = (struct IntuiMessage *)
GetMsg(window->UserPort)))
WaitPort(window->UserPort);
class = message->Class;
code = message->Code;
gadget = (struct Gadget *) message->IAddress;
ReplyMsg(message);
if (class == CLOSEWINDOW) break;
if (class == RAWKEY) OutConsole(code);
if (class == GADGETUP) {
switch (gadget->GadgetID) {
case 5 :
/* The crossfade gadget. Get the sample, using
GetSoundData, and put it in cfsound. Clear
the undo buffer (oldsound) and get the same
sample loaded into it. Call crossfade to alter
cfsound, then install it in the sampler with
a call to SetSoundData.
Then, clear out cfsound.
*/
if (!(GetSoundData(channel,
octave,cfsound))) {
clearsounddata(oldsound);
if (GetSoundData(channel,
octave,oldsound)) {
oldsound->data = 0;
}
crossfade(cfsound);
SetSoundData(channel,octave,cfsound);
clearsounddata(cfsound);
}
break;
case 6 :
/* This gadget simply sets the channel of the sampler
that we are looking at. Also, clear the undo buffer.
*/
channel = (GadgetSI6.LongInt - 1) & 0x0F;
clearsounddata(oldsound);
break;
case 7 :
/* This gadget sets the octave of the sample we are
looking at. Clear the undo buffer.
*/
octave = GadgetSI7.LongInt;
if (octave < 0) octave = 0;
if (octave > 9) octave = 9;
clearsounddata(oldsound);
break;
case 8 :
/* This is the undo command. Simply give the undo
buffer to the sampler, then clear the undo buffer.
*/
if (oldsound->data) {
SetSoundData(channel,octave,oldsound);
clearsounddata(oldsound);
}
break;
}
}
}
CloseWindow(window);
clearsounddata(oldsound);
clearsounddata(cfsound);
FreeMem(oldsound,sizeof(*oldsound));
FreeMem(cfsound,sizeof(*cfsound));
}
editcode(direction,command,buffer)
/* This is the edit routine provided to SoundScape
in the AddMidiPort call.
There is nothing in the way of data structures
that we would like any other modules to access,
nor is there anything to save or load with
environment loads and save. So, the GETSTATE,
SETSTATE, SAVESTATE, and LOADSTATE commands are
all ignored and the sample's length is set to
0.
However, USEREDIT indicates the user has clicked
twice on the cross fade icon and would like to
work with it. In that case, call the routine
'useredit' which puts up a window and lets the
user do that wild cross fade thing.
*/
char direction, command;
long *buffer;
{
static char not_editing = 1;
*buffer = 0;
switch (command) {
case USEREDIT :
if (not_editing) {
not_editing = 0;
useredit();
not_editing = 1;
}
break;
}
}
/* The main program is simple. Just open SoundScape to
get the address of the library vector, then close
the library (since this is a module and usually is
invoked by SoundScape when the first program opens
SoundScape, if it keeps the library count up, there
will be no way to close SoundScape.)
Check the version number. If it's below 2, this
SoundScape Sampler module doesn't support having
samples changed, so quit.
Else, add the module's port and wait for SoundScape
to shut it down.
*/
long SoundScapeBase;
long IntuitionBase;
main() {
SoundScapeBase = OpenLibrary("soundscape.library",0);
if (SoundScapeBase) {
IntuitionBase = OpenLibrary("intuition.library",0);
CloseLibrary(SoundScapeBase);
if (Version() > 1) {
thisport = AddMidiPort(opencode,closecode,
editcode,0,&crossfadeimage,0,-1,"cross fade");
SetTaskPri(FindTask(0),-20);
while (MidiPort(thisport)) Delay(100);
}
CloseLibrary(IntuitionBase);
}
}